#include <filesystem>
#include <fstream>
#include <iterator>
#include <vector>

namespace autodrive {
namespace perception {
/// @brief
/// @param path
/// @return
std::string read_text(std::filesystem::path const& path) noexcept(false);

/// @brief read text file
/// @tparam T data type
/// @param path file path
/// @param obj data object
template <typename T>
void read_text(std::filesystem::path const& path,
               std::vector<T>& data) noexcept(false) {
  if (!std::filesystem::exists(path)) {
    throw std::runtime_error("file " + path.string() + " does not exist");
  }
  std::ifstream iStream{path, std::ios::in};
  if (!iStream.is_open() || !iStream.good()) {
    throw std::runtime_error("failed to open file " + path.string());
  }

  try {
    data = {std::istream_iterator<T>(iStream), std::istream_iterator<T>()};
  } catch (const std::exception& e) {
    iStream.close();
    throw std::runtime_error(path.string() + " read error, " + e.what());
  } catch (...) {
    iStream.close();
    throw std::runtime_error(path.string() + " read error, unexpected");
  }
}

/// @brief
/// @tparam T
/// @param path
/// @param data
template <typename T>
void read_bin(std::filesystem::path const& path,
              std::vector<T>& data) noexcept(false) {
  if (!std::filesystem::exists(path)) {
    throw std::runtime_error("file " + path.string() + " does not exist");
  }

  std::ifstream iStream{path, std::ios::binary | std::ios::in | std::ios::ate};

  if (!iStream.is_open() || !iStream.good()) {
    throw std::runtime_error("failed to open file " + path.string());
  }

  try {
    auto byteSize{iStream.tellg()};
    auto size{byteSize / sizeof(T)};

    data.resize(size);

    iStream.seekg(0, iStream.beg);

    iStream.read(static_cast<char*>(static_cast<void*>(data.data())), byteSize);
    iStream.close();
  } catch (const std::exception& e) {
    iStream.close();
    throw std::runtime_error(path.string() + " read error, " + e.what());
  } catch (...) {
    iStream.close();
    throw std::runtime_error(path.string() + " read error, unexpected");
  }
}
}  // namespace perception
}  // namespace autodrive